Skip to content

Build one trace id per extracted compound context - #13033

Draft
dougqh wants to merge 5 commits into
dougqh/cold-span-fields-off-contextfrom
dougqh/primitive-extracted-trace-ids
Draft

dougqh wants to merge 5 commits into
dougqh/cold-span-fields-off-contextfrom
dougqh/primitive-extracted-trace-ids

Conversation

@dougqh

@dougqh dougqh commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

What Does This Do

Default compound extraction (Datadog, then W3C trace context) builds one trace id object per request instead of three, and parses each trace id once:

step before after
Datadog x-datadog-trace-id DDTraceId.from(…) builds a DD64bTraceId the low order bits and the raw string are kept
Datadog with _dd.p.tid restore128bTraceId builds a second, DD128bTraceId, object the one id is built in build(): DD128bTraceId from the parts, or DDTraceId.from(raw) for a 64-bit id
trace context merge DD128bTraceId.fromHex builds an id plus a copy of its 32 hex characters, only for traceIdMatch the traceparent's high and low order bits are compared directly; nothing is built
  • Datadog: the value is still parsed in accept, with the same LongStringUtils.parseUnsignedLong as DDTraceId.from. So an invalid id invalidates the context at the same point as before. A 64-bit id still keeps the header string as its cached toString().
  • W3C: the traceparent validation is shared. The full path still builds its id with DD128bTraceId.fromHex (one parse, with the cached hex string) and reads the parts from it. Only merge mode parses the parts on their own.

Motivation

TraceSegment work (APMLP-2049), part of a primitive trace-id view. Extraction holds the id as parts, and an object is built only where one is kept.

Not benchmarked yet. Expected: about −140 B per compound extract, from one DD64bTraceId plus one DD128bTraceId and a 32-character String.

Additional Notes

  • Corpus extension. CompoundExtractionGoldenTest gains invalid, negative and zero x-datadog-trace-id values. The first version of this change stored the raw id before parsing it, so an invalid id escaped build() as a NumberFormatException. The existing extractor tests caught it, but the golden corpus had no such input.
    • The corpus commit comes first; its golden was regenerated on the code before this change (1274 curated cases).
    • The change passes it, and the 10150-case cartesian corpus is identical.
    • Re-introducing the bug fails the golden.
  • One parse for a 64-bit Datadog id too. The new public DDTraceId.from(long, String) creates the id from the value accept already parsed and the header string it came from, exactly as DDTraceId.from(String) would, including the ZERO/MAX constants and the kept string. It's tested in DDTraceIdTest, including a leading-zero string.
  • Tests: the full dd-trace-core suite passes locally, except for 2 Docker-dependent TracerConnectionReliabilityTest cases and the order-dependent PendingTraceBufferTest.testingTracerFlareDumpWithMultipleTraces.

Stacked: master ← #13008 ← #13000 ← #13009 ← #13010 ← #13015 ← #13028 ← #13029 ← #13032 ← this PR.

🤖 Generated with Claude Code

@dougqh dougqh added comp: core Tracer core tag: performance Performance related changes tag: no release notes Changes to exclude from release notes type: refactoring comp: context propagation Trace context propagation tag: ai generated Largely based on code generated by an AI or LLM labels Oct 23, 2026
@datadog-datadog-us1-prod

datadog-datadog-us1-prod Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

🎯 Code Coverage (details)
• Patch Coverage: 97.14%
• Overall Coverage: 59.96% (+0.00%)

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: caf1cf9 | Docs | Give us feedback!

@dd-octo-sts

dd-octo-sts Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

🟢 Java Benchmark SLOs — All performance SLOs passed

Suite Status
Startup 🟢 pass

SLO thresholds are defined here based on automatically generated metrics. A warning is raised when results are within 5% of the threshold.

PR vs. master results
Scenario Candidate master Δ (95% CI of mean)
startup:insecure-bank:iast:Agent 13.97 s 13.96 s [-0.5%; +0.7%] (no difference)
startup:insecure-bank:tracing:Agent 12.91 s 12.96 s [-1.2%; +0.4%] (no difference)
startup:petclinic:appsec:Agent 17.18 s 17.06 s [-0.2%; +1.6%] (no difference)
startup:petclinic:iast:Agent 17.00 s 17.07 s [-1.3%; +0.5%] (no difference)
startup:petclinic:profiling:Agent 16.79 s 16.94 s [-1.9%; +0.2%] (no difference)
startup:petclinic:sca:Agent 17.22 s 17.04 s [+0.1%; +2.0%] (maybe worse)
startup:petclinic:tracing:Agent 16.31 s 16.24 s [-0.5%; +1.4%] (no difference)

Commit: caf1cf93 · CI Pipeline · Benchmarking Platform UI


Load and DaCapo benchmarks can be triggered manually in the GitLab pipeline. Results will appear in the Benchmarking Platform UI after completion.

dougqh and others added 3 commits October 23, 2026 16:17
An invalid, negative or zero x-datadog-trace-id must invalidate or
degrade the context exactly as before. The golden outputs are
regenerated on the code before the trace id change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Datadog extractor built a 64-bit trace id from x-datadog-trace-id
and then a second, 128-bit one once _dd.p.tid supplied the high order
bits. The trace context merge built a 128-bit id, plus a copy of its
hex, only to compare it. The Datadog extractor now keeps the parsed
low order bits and builds one trace id, and the merge compares the
traceparent's high and low order bits directly. The traceparent is
validated as before, and W3C-only extraction builds its trace id as
before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dougqh
dougqh force-pushed the dougqh/cold-span-fields-off-context branch from 4e4da0d to 55176e3 Compare October 23, 2026 20:26
@dougqh
dougqh force-pushed the dougqh/primitive-extracted-trace-ids branch from 0e5b9e7 to b8f07f0 Compare October 23, 2026 20:26
dougqh and others added 2 commits October 23, 2026 18:08
Adds DDTraceId.from(long, String), which creates the id from an already
parsed value and the string it was parsed from, as DDTraceId.from(String)
would. The Datadog extractor already parses x-datadog-trace-id when it
reads the header, so it now uses that instead of parsing the value a
second time when the id is 64-bit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp: context propagation Trace context propagation comp: core Tracer core tag: ai generated Largely based on code generated by an AI or LLM tag: no release notes Changes to exclude from release notes tag: performance Performance related changes type: refactoring

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant